import {
  Component,
  OnInit,
  OnChanges,
  OnDestroy,
  SimpleChanges,
  ElementRef,
  AfterViewInit,
  ViewChildren,
  ViewChild,
  QueryList,
  ChangeDetectionStrategy,
  ChangeDetectorRef
} from '@angular/core';
import { TickSeriesTickComponent } from "tick-series";
import { CmHttp } from "CmHttp";
import { Subject } from "rxjs/Subject";
import { Observable } from "rxjs/Observable";
import { Scheduler, } from "rxjs/Scheduler";
import { Subscription, } from "rxjs/Subscription";
import { SocketService } from "socket";
import { BASEURL } from "shared";

const SET_SIZE = 0,
  UPDATE_DATA = 1,
  SET_OFFSET = 2,
  SET_STRICK = 3;

interface HeightParams {
  containerHeight?: number;
  tickHeight?: number;
}

@Component({
  // moduleId: module.id,
  selector: 'tick-series',
  templateUrl: 'tick-series.component.html',
  // changeDetection: ChangeDetectionStrategy.OnPush,
  styleUrls: [
    "tick-series.component.less"
  ],
  inputs: [
    "stockSource",
    "stockSymbol"
  ]
})
export class TickSeriesComponent implements OnInit, OnChanges, AfterViewInit, OnDestroy {
  private mainSubscription: Subscription;
  private stockSource: Observable<any>;
  private currentSymbol;
  private store; // 仓库
  private heightInitializer = new Subject<HeightParams>();
  private scrollBarSource = new Subject<any>();
  private ticks;
  private allTicks;
  private backgroundList;
  @ViewChild("ticksContainer", { read: ElementRef })
  private ticksContainer: ElementRef;
  // @ViewChildren("ticksome", { read: ElementRef })
  // private tickElems: QueryList<ElementRef>;

  constructor(
    private http: CmHttp,
    private cdr: ChangeDetectorRef,
    private socket: SocketService
  ) {

  }

  ngOnInit() {
    // 当股票更换后更新仓库
    this.mainSubscription = this.stockSource.
      filter(e => e.symbol).
      distinctUntilChanged((pre, next) => {
        let flag = pre["symbol"] === next["symbol"];
        if (!flag) {
          this.socket.emit("unsub", { interval: "tickseries", symbol: pre["symbol"] });
        }
        return flag;
      }).
      switchMap(stock => {
        this.currentSymbol = stock["symbol"];
        return this.http.get(`${BASEURL}/stock/tickseries/${stock["symbol"]}`);
      }).
      subscribe(res => {
        this.socket.emit("sub", { interval: "tickseries", symbol: this.currentSymbol });
        this.store.next({
          type: UPDATE_DATA,
          payload: res
        })
      });

    // 状态仓库，维护当前数据，及数据数量
    this.store =
      new Subject().scan(
        (state, action) => {
          switch (action["type"]) {
            case SET_SIZE:
              return Object.assign({}, state, {
                size: action["payload"],
                ticksToShow: state["sticky"] ? state.ticks.slice(-state.size) : state.ticks.slice(state.ticks.length - action["payload"])
              });
            case UPDATE_DATA:
              return Object.assign({}, state, {
                ticks: action["payload"],
                ticksToShow: state.sticky ?
                  action["payload"].slice(-state.size) :
                  action["payload"].slice(Math.floor(state.offset * state.ticks.length), Math.floor(state.offset * state.ticks.length) + state.size)
              });
            case SET_OFFSET:
              return Object.assign({}, state, {
                offset: action["payload"],
                sticky: action["sticky"],
                ticksToShow: action["sticky"] ? state.ticks.slice(-state.size) : state.ticks.slice(Math.floor(action["payload"] * state.ticks.length), Math.floor(action["payload"] * state.ticks.length) + state.size)
              });
            case SET_STRICK:
              return Object.assign({}, state, { sticky: action["payload"] });
            default:
              return state;
          }
        }, {
          size: 9,
          offset: 0,
          ticks: [],
          sticky: true
        });
    this.mainSubscription.add(
      this.store.subscribe(state => {
        // console.debug("Tick State: ", state);
        this.allTicks = state.ticks;
        this.ticks = state.ticksToShow;
        this.scrollBarSource.next({
          sticky: state.sticky,
          amountOfTotal: state.ticks.length,
          amountOfVisible: state.ticksToShow.length
        });
        // this.cdr.markForCheck();
      })
    );

    this.mainSubscription.add(
      this.heightInitializer.
        distinctUntilChanged().
        subscribe(heightParams =>
          this.store.next({
            type: SET_SIZE,
            payload: this.calcSize(heightParams)
          })
        )
    );

    this.socket.on("TickSeries", tick => {
      console.debug("Tick Update: ", tick);
      this.store.next({
        type: UPDATE_DATA,
        payload: [...this.allTicks, Object.keys(tick).map(key => tick[key]).reduce(first => first)]
      })
    });
    // tick type
    // const TickType = {
    //   "2017-05-22 13:17:04": {
    //     balance: 6750,
    //     direction: 1,
    //     price: 7.5,
    //     time: "2017-05-22 13:17:04",
    //     volume: 9,
    //   }
    // };

    // 模拟Socket
    // Observable.interval(200).take(100).subscribe(time => {
    //   this.store.next({
    //     type: UPDATE_DATA,
    //     payload: [...this.allTicks, {
    //       time: Date.now(),
    //       price: Math.floor(Math.random() * 2000),
    //       volume: Math.floor(Math.random() * 2000),
    //       direction: Math.random() >= 0.5 ? 0 : 1
    //     }]
    //   })
    // });


    this.updateSize();
  }

  ngOnChanges(changes: SimpleChanges) {
    console.debug("Tick Change: ", changes);
    // if (changes["stockSymbol"]) {
    //   this.subject.next(changes["stockSymbol"].currentValue);
    // }
  }

  ngAfterViewInit() {
    // this.tickElems.changes.subscribe(change => this.updateSize(change.first));
    // console.debug("Tick Container: ", this);
  }

  ngOnDestroy() {
    if (this.mainSubscription) {
      this.mainSubscription.unsubscribe();
    }
    this.socket.emit("unsub", { interval: "tickseries", symbol: this.currentSymbol });
  }

  updateSize(tickElem?: ElementRef) {
    let params: HeightParams = {};
    params.containerHeight = (<HTMLElement>this.ticksContainer.nativeElement).getBoundingClientRect().height;
    params.tickHeight = 30;
    // params.tickHeight = (<HTMLElement>tickElem.nativeElement).getBoundingClientRect().height;
    this.heightInitializer.next(params);
  }

  updateVisibleData(pos) {
    console.debug("Scroll Pos: ", pos);
    this.store.next({
      type: SET_OFFSET,
      payload: pos.pos,
      sticky: pos.sticky
    });
  }

  onResizing(params: { window; target }) {
    this.updateSize();
    // this.calcSize({
    //   tickHeight: 30,
    //   containerHeight: params.target.height
    // });

  }

  calcSize(params: HeightParams) {
    let { containerHeight, tickHeight } = params;
    let sizeOfSingleCol = Math.max(6, Math.floor(containerHeight / tickHeight));
    this.backgroundList = new Array(sizeOfSingleCol).fill(1);
    return sizeOfSingleCol * 4;
  }


}